package com.esreport.logstash.tracker;

import com.esreport.Utils.FileUtil;
import com.esreport.Utils.RegExUtils;
import com.esreport.logstash.CollectorTask;
import com.esreport.logstash.cutter.Cutter;
import com.esreport.logstash.parser.LogParser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.concurrent.*;

/**
 * 日志挖掘
 *
 * @author xuweiwei
 * @date 2018/12/25
 */
@Slf4j
public class FileTracker<T> implements InitializingBean, Runnable {
    /**
     * 日志内容分割器
     */
    private Cutter cutter;
    /**
     * 日志内容解析器
     */
    private LogParser<T> parser;
    /**
     * 日志来源描述
     */
    private List<LogDescribe> logFileList = new ArrayList<LogDescribe>();

    /**
     * 队列
     */
    private Queue<T> queue = new ConcurrentLinkedQueue();

    /**
     * 日志文件对应Map
     */
    private Map<String, LogFile> logFileMap = new ConcurrentHashMap<>();

    private static  ExecutorService executor = Executors.newFixedThreadPool(5) ;


    /**
     * 日志文件过滤,把符合的未记录的日志找出来
     *
     * @param dir      日志目录
     * @param fileList 日志文件
     * @param regex    日志文件名正则表达式
     * @return
     */
    public List<File> filter(File dir, List<File> fileList, String regex) {
        List<File> result = new ArrayList();
        String dirPath = dir.getAbsolutePath();
        for (File f : fileList) {
            String fileAbsolutePath = f.getAbsolutePath();
            String filePath = fileAbsolutePath.substring(dirPath.length() + 1);
            if ( !logFileMap.containsKey(fileAbsolutePath) && RegExUtils.matches(filePath, regex) ) {
                result.add(f);
            }
        }
        return result;
    }


    @Override
    public void run() {
        for (; ; ) {
            //清除不存在的文件
            clear();
            Iterator<Map.Entry<String, LogFile>> iter = logFileMap.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String, LogFile> entry = iter.next();
                LogFile logFile = entry.getValue();
                long lastModified = logFile.getLastModified();
                long fileLastModified = logFile.getFile().lastModified();
                if (fileLastModified > lastModified) {
                    log.info("日志文件更改:{}", logFile.getFile().getAbsolutePath());
                    if(!logFile.isLocked()) {
                        executor.execute(new CollectorTask<T>(cutter, parser, logFile, queue));
                    }
                }
            }
            //扫描新文件
            searchFile();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        init();
    }

    /**
     * 挖掘器初始化
     */
    public void init() {
        log.info("日志文件探索模块开始启动");
        for (LogDescribe describe : logFileList) {
            describe.analyzer();
        }
        searchFile();
        executor.execute(this);
    }

    /**
     * 搜索新增文件
     */
    public void searchFile() {
        for (LogDescribe describe : logFileList) {
            File dir = new File(describe.getDir());
            if (!dir.isDirectory()) {
                log.error("{} 不是目录", dir.getAbsolutePath());
                continue;
            }
            List<File> fileList = FileUtil.recursiveFile(dir);
            if (fileList.isEmpty()) {
                continue;
            }
            List<File> logFile = filter(dir, fileList, describe.getRegexDesc());
            for (File f : logFile) {
                try {
                    LogFile lf = new LogFile(f);
                    logFileMap.put(f.getAbsolutePath(), lf);
                    log.info("发现新文件,{}", f.getAbsolutePath());
                    if (lf.length() > 0) {
                        executor.execute(new CollectorTask<T>(cutter, parser, lf, queue));
                    }
                } catch (FileNotFoundException e) {
                    log.error("文件不存在:{}", f.getAbsolutePath(), e);
                }

            }
        }
    }

    /**
     * 清理删除文件
     */
    public void clear() {
        Iterator<Map.Entry<String, LogFile>> iter = logFileMap.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, LogFile> entry = iter.next();
            LogFile logFile = entry.getValue();
            if (!logFile.exist()) {
                logFile.destroy();
                iter.remove();
                log.info("文件不存在,路径:{}",logFile.getFile().getAbsolutePath());
            }
        }
    }


    public void setCutter(Cutter cutter) {
        this.cutter = cutter;
    }

    public void setParser(LogParser<T> parser) {
        this.parser = parser;
    }

    public void setLogFileList(List<LogDescribe> logFileList) {
        this.logFileList = logFileList;
    }

    public Queue<T> getQueue() {
        return queue;
    }
}
